home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
DEMON
/
RISCOS2
/
TCP_131S.ARC
/
s
/
caller
next >
Wrap
Text File
|
1991-09-02
|
3KB
|
120 lines
; Trace back through the function call thread, and return the name of the
; function "n" calls up.
;
; e.g. if you have (in C)
;
; extern char *caller(int);
;
; void foo (void)
; {
; bar();
; }
;
; void bar (void)
; {
; char *f0 = caller(0);
; char *f1 = caller(1);
; }
;
; f0 should contain "bar", and f1 should contain "foo".
;
; I tend to use caller(1) to debug things like memory problems, where I
; use things like
;
; void *xmalloc(size_t size)
; {
; void *res = malloc(size);
; if (res == NULL)
; {
; fprintf(stderr, "Error calling malloc(%d) from %s\n",
; size, caller(1));
; exit(1);
; }
; return res;
; }
;
; [This use of caller(1) is OK - see below - as it is unlikely that anything
; will call xmalloc() and not use the result somehow...]
;
;
; NOTE: This routine RELIES on the Risc-OS Arm procedure call standard
; binding (APCS-R). In particular, it will NOT work on code
; compiled under Ansi C v2.00 or earlier!
;
; NOTE: The parameter "n" passed to caller() is NOT always what you might
; think! Basically, because Acorn C is very good at optimising tail-
; recursive function calls into simple branches. For example, in the
; example above, foo() would be optimised to a simple "B bar"
; instruction. So f1 will, in fact, be the name of foo()'s caller (or
; possibly even further up the calling tree!), rather than "foo".
; In general, caller(0) is always safe, and caller(1) is OK in most
; cases. caller(n) for n = 2 and above are more risky, basically
; getting worse as n increases.
;
; NOTE: If you "back up" into functions compiled without function names
; embedded in the code (eg, C library functions), caller(n) will
; CRASH. Sorry - but there is no way that I can see to recognise
; this situation...
;
; (Basically, the usual disclaimers all apply, in spades!).
;
a1 RN 0
a2 RN 1
a3 RN 2
a4 RN 3
v1 RN 4
v2 RN 5
v3 RN 6
v4 RN 7
v5 RN 8
v6 RN 9
sl RN 10
fp RN 11
ip RN 12
sp RN 13
lr RN 14
pc RN 15
AREA |Caller|, CODE, READONLY
EXPORT caller
01
DCB "caller",0
ALIGN
DCD &FF000000 :OR: ( {PC} - %B01 )
caller
MOVS a2, fp ; If frame pointer is 0 then
ADREQ a1, null ; there is no backtrace structure
MOVEQS pc, lr
02 TEQ a1, #0 ; Go back a1 frames...
BEQ %F03
LDR a2, [a2, #-12] ; Get caller's frame pointer
TEQ a2, #0 ; If 0, no backtrace structure
ADREQ a1, null
MOVEQS pc, lr
SUB a1, a1, #1
B %B02
03 LDR a2, [a2] ; Get caller's PC (return data save)
BIC a2, a2, #&FC000003 ; Convert to an address
SUB a2, a2, #12 ; Go to return data save instruction
04 LDR a3, [a2, #-4]! ; Get previous word
MOV a4, a3, LSR #24 ; Test top 8 bits
TEQ a4, #&FF ; If they're FF, we've found the name
BNE %B04
BIC a3, a3, #&FF000000 ; Get the name offset
SUB a1, a2, a3 ; Point to the caller's name
MOVS pc, lr ; Return
null
DCB "",0
ALIGN
END